#include "const/oPreDefine.h"
#include "platform/oAINode.h"
#include "platform/oAI.h"
#include "platform/oAICache.h"
#include "platform/oProperty.h"
#include "platform/oUnit.h"
using namespace platform;

oInstinct::oInstinct( const string& propName, oAILeaf* node ):
_actionNode(node),
_propName(propName),
_handler(&oInstinct::onInstinctPropertyChanged, this)
{
	_actionNode->retain();
}

oInstinct::~oInstinct()
{
	CC_SAFE_RELEASE_NULL(_actionNode);
}

void oInstinct::install(oUnit* unit)
{
	oProperty* prop = unit->properties.get(_propName);
	if (prop)
	{
		prop->changed += _handler;
	}
}

void oInstinct::uninstall( oUnit* unit )
{
	oProperty* prop = unit->properties.get(_propName);
	if (prop)
	{
		prop->changed -= _handler;
	}
}

void oInstinct::onInstinctPropertyChanged( oUnit* unit, float oldValue, float newValue )
{
	oAI::_self = unit;
	oAI::_lastDeltaInstinctProperty = newValue - oldValue;
	_actionNode->doAction();
}

oInstinct* oInstinct::create( const string& propName, oAILeaf* node )
{
	oInstinct* instinct = new oInstinct(propName, node);
	instinct->autorelease();
	return instinct;
}

oAINode::~oAINode()
{
	oAINode::clear();
}

void oAINode::addChild( oAILeaf* node )
{
	_children.push_back(node);
	node->retain();
}

void oAINode::removeChild( oAILeaf* node )
{
	for (auto it = _children.begin();it != _children.end();it++)
	{
		if ((*it) == node)
		{
			_children.erase(it);
			node->release();
			break;
		}
	}
}

void oAINode::clear()
{
	BOOST_FOREACH(oAILeaf* node, _children)
	{
		node->release();
	}
	_children.clear();
}

const vector<oAILeaf*>& oAINode::getChildren() const
{
	return _children;
}

oSelNode::oSelNode()
{ }

bool oSelNode::doAction()
{
	BOOST_FOREACH(oAILeaf* node, _children)
	{
		if (node->doAction())
		{
			return true;
		}
	}
	return false;
}

oSelNode* oSelNode::create()
{
	oSelNode* node = new oSelNode();
	node->autorelease();
	return node;
}

oSeqNode::oSeqNode()
{ }

oSeqNode* oSeqNode::create()
{
	oSeqNode* node = new oSeqNode();
	node->autorelease();
	return node;
}

bool oSeqNode::doAction()
{
	BOOST_FOREACH(oAILeaf* node, _children)
	{
		if (!node->doAction())
		{
			return false;
		}
	}
	return true;
}

oParSelNode::oParSelNode()
{ }

oParSelNode* oParSelNode::create()
{
	oParSelNode* node = new oParSelNode();
	node->autorelease();
	return node;
}

bool oParSelNode::doAction()
{
	bool result = true;
	BOOST_FOREACH(oAILeaf* node, _children)
	{
		if (!node->doAction())
		{
			result = false;
		}
	}
	return result;
}

oParSeqNode::oParSeqNode()
{ }

oParSeqNode* oParSeqNode::create()
{
	oParSeqNode* node = new oParSeqNode();
	node->autorelease();
	return node;
}

bool oParSeqNode::doAction()
{
	bool result = false;
	BOOST_FOREACH(oAILeaf* node, _children)
	{
		if (node->doAction())
		{
			result = true;
		}
	}
	return result;
}

bool oActNode::doAction()
{
	return oAI::self()->doIt(_actionId);
}

oAILeaf* oActNode::create()
{
	oActNode* node = new oActNode();
	node->_actionId = oAICache::action;
	node->autorelease();
	return node;
}

/** @brief condition_UnitCountCompare */
oConNode0::~oConNode0()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode0::doAction()
{
	return oAI::condition_UnitCountCompare(_relation, _compare);
}
oAILeaf* oConNode0::create()
{
	oConNode0* node = new oConNode0();
	node->_relation = oAICache::relation;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitTypeCountCompare */
oConNode1::~oConNode1()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode1::doAction()
{
	return oAI::condition_UnitTypeCountCompare(_relation, _type, _compare);
}
oAILeaf* oConNode1::create()
{
	oConNode1* node = new oConNode1();
	node->_relation = oAICache::relation;
	node->_type = oAICache::type;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitDistanceCompareCountCompare */
oConNode2::~oConNode2()
{
	CC_SAFE_DELETE(_compareDistance);
	CC_SAFE_DELETE(_compareCount);
}
bool oConNode2::doAction()
{
	return oAI::condition_UnitDistanceCompareCountCompare(_relation, _compareDistance, _compareCount);
}
oAILeaf* oConNode2::create()
{
	oConNode2* node = new oConNode2();
	node->_relation = oAICache::relation;
	node->_compareDistance = oAICache::compareOne;
	node->_compareCount = oAICache::compareTwo;
	oAICache::compareOne = nullptr;
	oAICache::compareTwo = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitHpCompareCountCompare */
oConNode3::~oConNode3()
{
	CC_SAFE_DELETE(_compareHp);
	CC_SAFE_DELETE(_compareCount);
}
bool oConNode3::doAction()
{
	return oAI::condition_UnitHpCompareCountCompare(_relation, _compareHp, _compareCount);
}
oAILeaf* oConNode3::create()
{
	oConNode3* node = new oConNode3();
	node->_relation = oAICache::relation;
	node->_compareHp = oAICache::compareOne;
	node->_compareCount = oAICache::compareTwo;
	oAICache::compareOne = nullptr;
	oAICache::compareTwo = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitHpPercentCompareCountCompare */
oConNode4::~oConNode4()
{
	CC_SAFE_DELETE(_comparePercent);
	CC_SAFE_DELETE(_compareCount);
}
bool oConNode4::doAction()
{
	return oAI::condition_UnitHpPercentCompareCountCompare(_relation, _comparePercent, _compareCount);
}
oAILeaf* oConNode4::create()
{
	oConNode4* node = new oConNode4();
	node->_relation = oAICache::relation;
	node->_comparePercent = oAICache::compareOne;
	node->_compareCount = oAICache::compareTwo;
	oAICache::compareOne = nullptr;
	oAICache::compareTwo = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitPropertyCompareCountCompare */
oConNode5::~oConNode5()
{
	CC_SAFE_DELETE(_compareProperty);
	CC_SAFE_DELETE(_compareCount);
}
bool oConNode5::doAction()
{
	return oAI::condition_UnitPropertyCompareCountCompare(_relation, _name, _compareProperty, _compareCount);
}
oAILeaf* oConNode5::create()
{
	oConNode5* node = new oConNode5();
	node->_relation = oAICache::relation;
	node->_name = oAICache::propName;
	node->_compareProperty = oAICache::compareOne;
	node->_compareCount = oAICache::compareTwo;
	oAICache::compareOne = nullptr;
	oAICache::compareTwo = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_SelfHpCompare */
oConNode6::~oConNode6()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode6::doAction()
{
	return oAI::condition_SelfHpCompare(_compare);
}
oAILeaf* oConNode6::create()
{
	oConNode6* node = new oConNode6();
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_SelfHpPercentCompare */
oConNode7::~oConNode7()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode7::doAction()
{
	return oAI::condition_SelfHpPercentCompare(_compare);
}
oAILeaf* oConNode7::create()
{
	oConNode7* node = new oConNode7();
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_SelfPropertyCompare */
oConNode8::~oConNode8()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode8::doAction()
{
	return oAI::condition_SelfHpPercentCompare(_compare);
}
oAILeaf* oConNode8::create()
{
	oConNode8* node = new oConNode8();
	node->_name = oAICache::propName;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_AnyUnitDoingAction */
bool oConNode9::doAction()
{
	return oAI::condition_AnyUnitDoingAction(_relation, _action);
}
oAILeaf* oConNode9::create()
{
	oConNode9* node = new oConNode9();
	node->_relation = oAICache::relation;
	node->_action = oAICache::action;
	node->autorelease();
	return node;
}

/** @brief condition_AnyUnitDistanceCompare */
oConNode10::~oConNode10()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode10::doAction()
{
	return oAI::condition_AnyUnitDistanceCompare(_relation, _compare);
}
oAILeaf* oConNode10::create()
{
	oConNode10* node = new oConNode10();
	node->_relation = oAICache::relation;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_AnyUnitHpCompare */
oConNode11::~oConNode11()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode11::doAction()
{
	return oAI::condition_AnyUnitHpCompare(_relation, _compare);
}
oAILeaf* oConNode11::create()
{
	oConNode11* node = new oConNode11();
	node->_relation = oAICache::relation;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_AnyUnitHpPercentCompare */
oConNode12::~oConNode12()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode12::doAction()
{
	return oAI::condition_AnyUnitHpPercentCompare(_relation, _compare);
}
oAILeaf* oConNode12::create()
{
	oConNode12* node = new oConNode12();
	node->_relation = oAICache::relation;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_AnyUnitPropertyCompare */
oConNode13::~oConNode13()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode13::doAction()
{
	return oAI::condition_AnyUnitPropertyCompare(_relation, _name, _compare);
}
oAILeaf* oConNode13::create()
{
	oConNode13* node = new oConNode13();
	node->_relation = oAICache::relation;
	node->_name = oAICache::propName;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_NearestUnitDoingAction */
bool oConNode14::doAction()
{
	return oAI::condition_NearestUnitDoingAction(_relation, _action);
}
oAILeaf* oConNode14::create()
{
	oConNode14* node = new oConNode14();
	node->_relation = oAICache::relation;
	node->_action = oAICache::action;
	node->autorelease();
	return node;
}

/** @brief condition_NearestUnitHpCompare */
oConNode15::~oConNode15()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode15::doAction()
{
	return oAI::condition_NearestUnitHpCompare(_relation, _compare);
}
oAILeaf* oConNode15::create()
{
	oConNode15* node = new oConNode15();
	node->_relation = oAICache::relation;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_NearestUnitHpPercentCompare */
oConNode16::~oConNode16()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode16::doAction()
{
	return oAI::condition_NearestUnitHpPercentCompare(_relation, _compare);
}
oAILeaf* oConNode16::create()
{
	oConNode16* node = new oConNode16();
	node->_relation = oAICache::relation;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_NearestUnitPropertyCompare */
oConNode17::~oConNode17()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode17::doAction()
{
	return oAI::condition_NearestUnitPropertyCompare(_relation, _name, _compare);
}
oAILeaf* oConNode17::create()
{
	oConNode17* node = new oConNode17();
	node->_relation = oAICache::relation;
	node->_name = oAICache::propName;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitWithTagDoingAction */
bool oConNode18::doAction()
{
	return oAI::condition_UnitWithTagDoingAction(_tag, _action);
}
oAILeaf* oConNode18::create()
{
	oConNode18* node = new oConNode18();
	node->_tag = oAICache::tag;
	node->_action = oAICache::action;
	node->autorelease();
	return node;
}

/** @brief condition_UnitWithTagDistanceCompare */
oConNode19::~oConNode19()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode19::doAction()
{
	return oAI::condition_UnitWithTagDistanceCompare(_tag, _compare);
}
oAILeaf* oConNode19::create()
{
	oConNode19* node = new oConNode19();
	node->_tag = oAICache::tag;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitWithTagHpCompare */
oConNode20::~oConNode20()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode20::doAction()
{
	return oAI::condition_UnitWithTagHpCompare(_tag, _compare);
}
oAILeaf* oConNode20::create()
{
	oConNode20* node = new oConNode20();
	node->_tag = oAICache::tag;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitWithTagHpPercentCompare */
oConNode21::~oConNode21()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode21::doAction()
{
	return oAI::condition_UnitWithTagHpPercentCompare(_tag, _compare);
}
oAILeaf* oConNode21::create()
{
	oConNode21* node = new oConNode21();
	node->_tag = oAICache::tag;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_UnitWithTagPropertyCompare */
oConNode22::~oConNode22()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode22::doAction()
{
	return oAI::condition_UnitWithTagPropertyCompare(_tag, _name, _compare);
}
oAILeaf* oConNode22::create()
{
	oConNode22* node = new oConNode22();
	node->_tag = oAICache::tag;
	node->_name = oAICache::propName;
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

/** @brief condition_SelfFaceLeft */
bool oConNode23::doAction()
{
	return oAI::condition_SelfFaceLeft();
}
oAILeaf* oConNode23::create()
{
	oConNode23* node = new oConNode23();
	node->autorelease();
	return node;
}

/** @brief condition_NearestUnitFaceLeft */
bool oConNode24::doAction()
{
	return oAI::condition_NearestUnitFaceLeft(_relation);
}
oAILeaf* oConNode24::create()
{
	oConNode24* node = new oConNode24();
	node->_relation = oAICache::relation;
	node->autorelease();
	return node;
}

/** @brief condition_UnitWithTagFaceLeft */
bool oConNode25::doAction()
{
	return oAI::condition_UnitWithTagFaceLeft(_tag);
}
oAILeaf* oConNode25::create()
{
	oConNode25* node = new oConNode25();
	node->_tag = oAICache::tag;
	node->autorelease();
	return node;
}

/** @brief condition_NearestUnitAtUnitLeft */
bool oConNode26::doAction()
{
	return oAI::condition_NearestUnitAtUnitLeft(_relation);
}
oAILeaf* oConNode26::create()
{
	oConNode26* node = new oConNode26();
	node->_relation = oAICache::relation;
	node->autorelease();
	return node;
}

/** @brief condition_UnitWithTagAtUnitLeft */
bool oConNode27::doAction()
{
	return oAI::condition_UnitWithTagAtUnitLeft(_tag);
}
oAILeaf* oConNode27::create()
{
	oConNode27* node = new oConNode27();
	node->_tag = oAICache::tag;
	node->autorelease();
	return node;
}

/** @brief condition_LastChangedInstanctPropertyDeltaCompare */
oConNode28::~oConNode28()
{
	CC_SAFE_DELETE(_compare);
}
bool oConNode28::doAction()
{
	return oAI::condition_LastChangedInstinctPropertyDeltaCompare(_compare);
}
oAILeaf* oConNode28::create()
{
	oConNode28* node = new oConNode28();
	node->_compare = oAICache::compareOne;
	oAICache::compareOne = nullptr;
	node->autorelease();
	return node;
}

const oConNodeFunc oConNode::creates[] = 
{
	&oConNode0::create,
	&oConNode1::create,
	&oConNode2::create,
	&oConNode3::create,
	&oConNode4::create,
	&oConNode5::create,
	&oConNode6::create,
	&oConNode7::create,
	&oConNode8::create,
	&oConNode9::create,
	&oConNode10::create,
	&oConNode11::create,
	&oConNode12::create,
	&oConNode13::create,
	&oConNode14::create,
	&oConNode15::create,
	&oConNode16::create,
	&oConNode17::create,
	&oConNode18::create,
	&oConNode19::create,
	&oConNode20::create,
	&oConNode21::create,
	&oConNode22::create,
	&oConNode23::create,
	&oConNode24::create,
	&oConNode25::create,
	&oConNode26::create,
	&oConNode27::create,
	&oConNode28::create
};

const uint32 oConNode::MAX_CONNODE = sizeof(creates) / sizeof(oConNodeFunc);

oAILeaf* oConNode::create( uint32 index )
{
	if (index < MAX_CONNODE)
	{
		return creates[index]();
	}
	return nullptr;
}
